#!/bin/bash

#Locations
BUILD_DIR="${BUILD_DIR:-@PROJECT_BINARY_DIR@}"
RUNTIME_DIR="${RUNTIME_DIR:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_LOC>}"
DEPLOY_DIR="${DEPLOY_DIR:-${BUILD_DIR}/deploy}"

#Name & Group
RUNTIME_NAME="${RUNTIME_NAME:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_NAME>}"
RUNTIME_GROUP="${RUNTIME_GROUP:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_GROUP>}"

#commands
COMMANDS=${COMMANDS:-"$<JOIN:$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_COMMANDS>, >"}

#containers
$<JOIN:$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_CONTAINERS>,
>

#container arguments
$<JOIN:$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_ARGUMENTS>,
>

#release files
$<JOIN:$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RELEASE_FILES>,
>

#Options
TERM_CMD="${TERM_CMD:-xterm}"
TERM_OPTS="${TERM_OPTS:-}"
USE_TERM="${USE_TERM:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_USE_TERM>}"
RELEASE_SH="${RELEASE_SH:-}"
WAIT_FOR_CONTAINER="${WAIT_FOR_CONTAINER:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_WAIT_FOR_CONTAINER>}"
WAIT_FOR_CMD="${WAIT_FOR_CMD:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_WAIT_FOR_COMMAND>}"
LOG_TO_FILES="${LOG_TO_FILES:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_LOG_TO_FILES>}"
KILL_OPTS="${KILL_OPTS:--2}" #default is -2, e.g. SIGINT
PATIENCE="${PATIENCE:-5}" #in seconds

PIDS=""
RUNTIME_STARTTIME=$(date +"%s")
trap stop_all INT

##functions
function rt_init() {
    rm -fr ${RUNTIME_DIR}/run #contains pids, etc
    rm -fr ${RUNTIME_DIR}/logs
    mkdir ${RUNTIME_DIR}/run
    mkdir ${RUNTIME_DIR}/logs
    echo "Name: ${RUNTIME_NAME}" > ${RUNTIME_DIR}/logs/init.log
    echo "Start time: ${RUNTIME_STARTTIME}" >> ${RUNTIME_DIR}/logs/init.log
}

function rt_start_all() {
    echo ""
    echo ""
    echo "********** Starting runtime ${RUNTIME_NAME} **********"
    for CONTAINERS_INDEX in "${!CONTAINERS_NAMES[@]}"
    do
        rt_run_deployment ${CONTAINERS_INDEX}
    done

    for CMD in ${COMMANDS}; do
        rt_run_cmd "${CMD}"
    done
}

function rt_stop_all() {
    echo "********** Stopping runtime ${RUNTIME_NAME} **********"
    for PID in ${PIDS}; do
        echo "Sending signal to ${PID}"
        kill ${KILL_OPTS} ${PID} 2> /dev/null; true
    done
}

function rt_stop() {
    PIDS=$@
    echo "Stopping pids ${PIDS}"
    kill ${KILL_OPTS} ${PIDS} 2> /dev/null; true
}

function rt_run_deployment() {
    INDEX=$1
    DEPLOYMENT=${CONTAINERS_NAMES[${INDEX}]}
    CONTAINERS_DIR=${CONTAINERS_DIRS[${INDEX}]}
    ARGS=${CONTAINERS_ARGUMENTS[${INDEX}]}
    LOG_FILE="${RUNTIME_DIR}/logs/${DEPLOYMENT}.log"
    DEBUG_OPTS=${CONTAINERS_DEBUG_OPTS[${INDEX}]}

    echo ""
    echo "Starting deployment ${DEPLOYMENT}"
    cd ${CONTAINERS_DIR}
    if [ -d .cache ] ; then
        echo "  Clearing cache"
        rm -fr .cache
    fi
    if [ -e release.sh ] ; then
        . ./release.sh #run deployment release
    fi
    echo "  Workdir: ${CONTAINERS_DIR}"
    echo "  Cmd used: '${DEBUG_OPTS} ./${DEPLOYMENT} ${ARGS}'"
    if [ "${USE_TERM}" = "TRUE" ] ; then
        if [ "${LOG_TO_FILES}" = "TRUE" ] ; then
            echo "  Using log file ${LOG_FILE}"
            ${TERM_CMD} ${TERM_OPTS} -e "${DEBUG_OPTS} ./${DEPLOYMENT} ${ARGS} &> ${LOG_FILE}"  &> /dev/null &
        else
            ${TERM_CMD} ${TERM_OPTS} -e "${DEBUG_OPTS} ./${DEPLOYMENT} ${ARGS}" &> /dev/null &
        fi
    else #run in this shell
        if [ "${LOG_TO_FILES}" = "TRUE" ] ; then
            echo "  Using log file ${LOG_FILE}"
            ${DEBUG_OPTS} ./${DEPLOYMENT} ${ARGS} &> ${LOG_FILE} &
        else
            ${DEBUG_OPTS} ./${DEPLOYMENT} ${ARGS} &
        fi
    fi
    PID=$!
    echo "  Pid of deployment '${DEPLOYMENT}' is ${PID}"
    if [ ! -z "${WAIT_FOR_CONTAINER}" -a "${CONTAINERS_DIR}" = "${WAIT_FOR_CONTAINER}" ] ; then
        WAIT_FOR_PID=${PID}
        echo "${PID}" > ${RUNTIME_DIR}/run/wait_for_pid
    else
        PIDS="${PID} ${PIDS}"
        echo "${PIDS}" > ${RUNTIME_DIR}/run/pids
    fi
    cd - > /dev/null
}

function rt_run_cmd() {
    CMD="$1"
    echo ""
    echo "Starting command '${CMD}'"
    read CMD_NAME _ <<< ${CMD}
    LOG_FILE="${RUNTIME_DIR}/logs/${CMD_NAME}.log"
    WD="${RUNTIME_DIR}/${CMD_NAME}"
    if [ -d {WD} ] ; then
        echo "  Clearing previous workdir for command '${CMD}'"
        rm -fr ${WD}
    fi
    echo "  Workdir: ${WD}"
    mkdir -p ${WD}
    cd ${WD}
    if [ "${USE_TERM}" = "TRUE" ] ; then
        if [ "${LOG_TO_FILES}" = "TRUE" ] ; then
            echo "  Using log file ${LOG_FILE}"
            ${TERM_CMD} ${TERM_OPTS} -e "${CMD} &> ${LOG_FILE}" &> /dev/null &
        else
            ${TERM_CMD} ${TERM_OPTS} -e "${CMD}" &> /dev/null &
        fi
    else
        if [ "${LOG_TO_FILES}" = "TRUE" ] ; then
            echo "  Using log file ${LOG_FILE}"
            ${CMD} &> ${LOG_FILE} &
        else
            ${CMD} &
        fi
    fi
    PID=$!
    echo "  Pid of command '${CMD}' is ${PID}"
    if [ ! -z "${WAIT_FOR_CMD}" -a "${CMD}" = "${MWAIT_FOR_CMD}" ] ; then
        WAIT_FOR_PID=${PID}
        echo "${PID}" > ${RUNTIME_DIR}/run/wait_for_pid
    else
        PIDS="${PID} ${PIDS}"
        echo "${PIDS}" > ${RUNTIME_DIR}/run/pids
    fi
    cd - > /dev/null
}

function rt_wait_for() {
    RESULT=0
    echo ""
    echo "Waiting for pid ${WAIT_FOR_PID}"
    if wait ${WAIT_FOR_PID}; then
        echo "${WAIT_FOR_PID} exited normal"
    else
        echo "${WAIT_FOR_PID} exited with error"
        RESULT=1
    fi

    echo "Signalling pids '${PIDS}' with '${KILL_OPTS}'"
    kill ${KILL_OPTS} ${PIDS}
    echo -n "Waiting "
    TIMES=${PATIENCE}
    for (( I=1; I<=TIMES; I++ ))
    do
        echo -n "."
        kill -0 ${PIDS} &> /dev/null
        if [ $? -eq 1 ] ; then #e.g. no such process result
            #all process stopped
            break
        else
            sleep 1
        fi
    done
    echo ""

    for PID in ${PIDS}; do
        kill -0 ${PID} &> /dev/null
        if [ $? -eq 0 ] ; then
            NAME=$(ps -p ${PID} -o comm | tail -n 1)
            echo "Out of patience, killing process '${NAME}' (${PID}), with kill -9"
            kill -9 ${PID}
        fi
    done
}


if [ -z "${RELEASE_SH}" ] ; then
    true #pass
elif [ -e "${RELEASE_SH}" ]; then #absolute release file
    source ${RELEASE_SH}
elif [ -e "${RUNTIME_DIR}/${RELEASE_SH}" ] ; then #release file in runtime dir
    source ${RUNTIME_DIR}/${RELEASE_SH}
elif [ -e "${BUILD_DIR}/${RELEASE_SH}" ] ; then #release file in build dir
    source ${BUILD_DIR}/${RELEASE_SH}
fi
